// prefetcher.bpf.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "prefetcher.h"

char LICENSE[] SEC("license") = "GPL";

// 对应设计图中的 "eBPF 哈希表 (PID -> 访问历史)"
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, __u32); // PID
    __type(value, struct access_history);
} history_map SEC(".maps");

// 对应设计图中的 "eBPF 环形缓冲区"
struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024); // 256 KB
} events SEC(".maps");

// 这是 tracepoint 的上下文结构，根据你的 format 输出定义
struct trace_event_raw_page_fault_user {
    unsigned short common_type;
    unsigned char common_flags;
    unsigned char common_preempt_count;
    int common_pid;
    unsigned long address;
    unsigned long ip;
    unsigned long error_code;
};

SEC("tracepoint/exceptions/page_fault_user")
int handle_page_fault(struct trace_event_raw_page_fault_user *ctx) {
    __u32 pid = bpf_get_current_pid_tgid() >> 32;
    unsigned long fault_addr = ctx->address;

    // 过滤掉内核线程
    if (pid == 0) {
        return 0;
    }

    struct access_history *hist = bpf_map_lookup_elem(&history_map, &pid);
    if (!hist) {
        // 首次访问，创建新记录
        struct access_history new_hist = {};
        new_hist.addresses[0] = fault_addr;
        new_hist.timestamps[0] = bpf_ktime_get_ns();
        new_hist.current_idx = 1;
        new_hist.stable_count = 0;
        new_hist.last_stride = 0;
        bpf_map_update_elem(&history_map, &pid, &new_hist, BPF_ANY);
        return 0;
    }

    __u32 prev_idx = (hist->current_idx - 1 + MAX_HISTORY_SIZE) % MAX_HISTORY_SIZE;
    unsigned long last_addr = hist->addresses[prev_idx];
    __u64 last_ts = hist->timestamps[prev_idx];
    __u64 current_ts = bpf_ktime_get_ns();

    // 时间窗口检查
    if (current_ts - last_ts > TIME_WINDOW_NS) {
        hist->stable_count = 0; // 超时，重置稳定计数
    }

    long current_stride = fault_addr - last_addr;

    if (current_stride != 0 && current_stride == hist->last_stride) {
        hist->stable_count++;
    } else {
        hist->stable_count = 1; // 步长变化，重置为1
    }

    hist->last_stride = current_stride;

    // 检查是否达到稳定模式阈值
    if (hist->stable_count >= DETECTION_THRESHOLD) {
        struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
        if (e) {
            e->pid = pid;
            e->stride = current_stride;
            e->fault_addr = fault_addr;
            bpf_ringbuf_submit(e, 0);
        }
        hist->stable_count = 0; // 上报后重置，避免频繁上报
    }

    // 更新历史记录
    __u32 current_idx = hist->current_idx % MAX_HISTORY_SIZE;
    hist->addresses[current_idx] = fault_addr;
    hist->timestamps[current_idx] = current_ts;
    hist->current_idx++;
    
    bpf_map_update_elem(&history_map, &pid, hist, BPF_ANY);

    return 0;
}